home *** CD-ROM | disk | FTP | other *** search
- (c) Copyright 1991 Commodore-Amiga, Inc. All rights reserved.
- The information contained herein is subject to change without notice,
- and is provided "as is" without warranty of any kind, either expressed
- or implied. The entire risk as to the use of this information is
- assumed by the user.
-
-
-
-
- Using SetFunction() in a Debugger
-
-
- By Ewout Walraven
-
-
-
- The Amiga OS consists of a set of libraries (and devices), which reside
- in ROM or on disk. These libraries provide a set of routines which are
- shared by the Amiga tasks (hence the name shared library).
-
- The way in which an Amiga library is organized allows a programmer to
- change where the system looks for a library routine. Exec provides a
- function to do this: SetFunction(). The SetFunction() routine redirects
- a library function call to an application-supplied function (Although
- this article doesn't address it, SetFunction() can also be used on Exec
- devices). The SetPatch utility uses SetFunction(). SetPatch is a
- program which replaces some OS routines with improved ones, primarily to
- fix bugs in ROM libraries.
-
- Normally, programs should not attempt to ``improve'' library functions.
- Because most programmers do not know exactly what system library
- functions do internally, OS patches can do more harm than good. However,
- a useful place to use SetFunction() is in a debugger. Using
- SetFunction(), a debugger can reroute library calls to a debugging
- function. The debugging function can inspect the arguments to a library
- function call before calling the original library routine (if everything
- is OK). Such a debugging function doesn't do any OS patching, it
- merely inspects.
-
- SetFunction() is also useful for testing an application under conditions
- it does not encounter normally. For example, a debugging program can
- force a program's memory allocations to fail or prevent a program's
- window from opening. This allows a programmer to find bugs that only
- arise under special circumstances. Some programs that use SetFunction()
- for debugging purposes are IO_Torture, Memoration and MungWall. A real
- watchdog is Wedge, which, as its name implies, allows you to install a
- wedge for practically every function of a standard library and inform
- you about the register values passed to the function. These types of
- debugging tools helped debug release 2.0 of the OS and found bugs and
- 1.3 dependencies in commercial applications.
-
- Although useful, SetFunction()ing library routines poses several
- problems. First of all, the wedge routine will have to be re-entrant,
- like all Exec library functions. Secondly, there is always a problem
- with removing the wedge. If another task has SetFunction()ed the same
- library routine as the debugger (a very real possibility), it is not
- normally possible to remove the first wedge, since the other task
- depends on the presence of your task's code. This would force your task
- to hang around, waiting for the other task(s) to remove their wedges.
- You also need to know when it is safe to unload your debugging code.
- Removing it while another task is executing it will quickly lead to a
- hopelessly crashed system.
-
- For those of you who might be thinking about writing down the ROM
- addresses returned by SetFunction() and using them in some other
- programs: Forget It. The address returned by SetFunction() is only good
- on the current system at the current time. Blindly jumping into ROM
- will cause your programs to break.
-
-
-
- Exec Library Structure
-
- When a library is opened for the first time, a library node structure, a
- jump table, and a data area are created in RAM.
-
- The library node structure address is the base address of the library.
- OpenLibrary() returns this base address. The library's jump table,
- which directly precedes the library node in RAM, consists of six byte
- long entries containing a jump instruction (JMP) to a corresponding
- library function. The jump table is initialized when Exec opens the
- library. Each function's entry in the jump table (also known as a
- vector) is always a constant (negative) offset from the library base.
- These fixed negative offsets are known as Library Vector Offsets (LVO).
- Note that the first four function vectors are reserved for use by Exec.
- They point to standard library functions for opening, closing, and
- expunging the library, plus there is space reserved for a fourth
- function vector. The base address of a library is determined
- dynamically when the library is loaded into RAM. See the Exec
- introduction chapter in the ROM Kernel Manual: Libraries and Devices for
- more information on libraries.
-
- The SetFunction() routine replaces an LVO address with a new address
- which points to the wedge routine. SetFunction() returns the old vector
- address, which the wedge routine can use to call the original library
- function from within the wedge. Note that if another task
- SetFunction()s the same library function, SetFunction() returns the
- address of your debugging routine (to the second task) as the old
- vector. At that point your task can no longer exit since that would
- mean that that other task has an invalid pointer to your function and
- will most likely crash the system when it tries to use your function.
-
- There is a way around this problem. Instead of SetFunction()ing a
- library function with the address of your wedge code, build your own
- jump table and use the addresses of its entries as arguments to
- SetFunction() calls. This method allows you to unload your code when
- you want to because if another task SetFunction()s your routine, that
- task will get a pointer to a jump table entry, not your routine.
-
- Now when you want to exit, all you need to do is replace the entries in
- your jump table which point to your functions with the original function
- vectors which were returned by SetFunction(). By not freeing the memory
- allocated for the jump table your task can exit any time, regardless of
- other tasks which SetFunction()ed the same library routines. The other
- task(s) will never know what happened.
-
- The next time the debugger is executed, it looks for the jump table it
- left behind and replaces the entries in it with pointers to its own
- functions. Incidentally, this is an easy way to provide a mechanism to
- determine if your debugging program has already been installed.
-
-
-
- Caveats
-
- There are some things to keep in mind when using SetFunction(). The
- scheme described above can force a second task to hang around forever if
- it SetFunction()ed a routine before you, since your debugger will not
- normally release its handle on the second task's function. Whenever
- possible, install jump table based debuggers before any other
- SetFunction()ing program (but after SetPatch of course).
-
- Some debuggers interpret the return address of the caller. When a
- debugger jumps (JMP) to (what it thinks is) the original function, there
- will be no problem. However, if a debugger performs a JSR to a second
- debugging function which interprets the return address, the second
- debugging function will receive the first debugging function's return
- address (the one that performed the JSR) rather than the return address
- of the application that called the library function in the first place.
- This can confuse the second debugger. Two good examples of this are
- Scratcher and MungWall, which both SetFunction() FreeMem(). MungWall
- looks at the return address of the caller. Since Scratcher calls the
- old FreeMem() function with a JSR instruction, it would mislead MungWall
- if run after it. Preferably, debuggers that interpret the return
- address should be started after other debuggers.
-
-
- Although it is not common, some library functions call other library
- functions and depend on certain scratch registers to contain valid
- values. SetFunction()ing one of these functions is likely to change the
- values in these scratch registers, leading to problems. Because these
- dependencies are not always documented, you might innocently run into
- one. Scratcher is an excellent tool for finding such dependencies.
-
- In the past, some system functions did not have a JMP vector in their
- entry in the LVO table. Instead, the actual function was in the jump
- table. SetFunction() will not work on such a function.
-
- Any debugging routine should be careful not to call the function it has
- patched with SetFunction(), either directly or indirectly. Doing so
- will likely cause a stack overflow and crash the machine. This may seem
- a bit obvious until you consider how easy it is to indirectly call a
- system routine. Many system functions are not atomic. They have to
- call lower level system functions. If you call a higher level system
- functions in the debugging code and you have SetFunction()ed one of the
- routines the high level function uses, the machine will probably crash
- from a stack overflow.
-
- Using SetFunction() on disk-based libraries and devices requires a
- little extra care. Unlike a ROM library, libraries (and devices) loaded
- into RAM can be expunged when memory gets low. To prevent the system
- from expunging a library (or device) you have SetFunction()ed, either
- keep the library (or device) opened, or use SetFunction() to patch the
- library's expunge function.
-
- Remember that when you install a wedge, another program can call it
- almost instantly. Because of this, the wedge should be completely set
- up before you install it.
-
- Note that dos.library is now a standard library and can be
- SetFunction()ed as of V36. Before V36 you would have to Forbid(), get
- the six original bytes of the entry in the function vector table,
- install the new vector, perform a SumLibrary() and then Permit().
-
- If it is necessary to put debugging code into a Forbid() or Disable()
- state, keep it in that state for as little time as possible to limit
- system slowdown. Remember that you cannot Disable() for more than 250
- microseconds. Be sure to read the Disable()/Enable() Autodocs before
- using them.
-
-
-
- An Example Debugger
-
- The usage of SetFunction() is shown by the example debugging program at
- the end of this article, ISpy. ISpy uses a semaphore to gain access to
- its jump table. This jump table contains pointers to the wedge
- routines. When executed, each wedge routine puts a shared lock on the
- semaphore to indicate that the code is being executed. To get an idea
- of who is calling the debugger entries, ISpy uses a little assembler
- stub to load a4 with the address of the stack of the caller and calls a
- C routine where the actual (simple) argument checking is done. When
- ISpy is signalled to exit, it tries to get an exclusive lock on the
- semaphore in a Forbid()en state. If this succeeds, it can safely assume
- its code is not being executed at the moment and can therefore place the
- original function vectors in the jump table and exit, leaving the
- semaphore behind. This semaphore is also used to check whether ISpy is
- already installed. If so, the new instance will exit immediately.
- Because of the use of shared semaphore locks, this program will only run
- with V37. By using a global counter (which is incremented each time a
- function is entered and decremented when it is exited) ISpy can be
- adapted to V33. Because of the way ISpy is set up, it is very easy to
- add argument checking front ends for functions, and have multiple
- versions of ISpy for different libraries.
-
-
-
- Memoration and Scratcher by Bill Hawes. IO_Torture by Bryce Nesbitt.
- Wedge and DevMon by Carolyn Scheppner. MungWall by Ewout Walraven
- (inspired by Memwall by Randell Jesup and MemMung by Bryce Nesbitt).
-
-
- =======================================================
-
- ;/* Execute me to compile with SASC 5.10a
- lc -b1 -cfist -d0 -O -v -j73 ispy.c
- asm -iINCLUDE: ispy_stubs.asm
- blink from lib:c.o ispy.o ispy_stubs.o LIB lib:amiga.lib lib:lcnb.lib lib:debug.lib SC SD ND DEFINE __main=__tinymain
- quit
- ** ISpy. AmigaMail SetFunction() example.
- **
- ** Copyright (c) 1991 Commodore-Amiga, Inc.
- ** All Rights Reserved
- **
- */
-
-
- #include <exec/types.h>
- #include <exec/execbase.h>
- #include <exec/memory.h>
- #include <exec/semaphores.h>
- #include <dos/dos.h>
- #include <libraries/gadtools.h>
- #include <string.h>
- #include <dos.h>
-
- #include <clib/dos_protos.h>
- #include <clib/exec_protos.h>
- #include <clib/intuition_protos.h>
-
- #ifdef LATTICE
- int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */
- int chkabort(void) { return(0); }
- #endif
-
- #define ASM __asm __saveds
- #define REG(x) register __## x
-
- #ifdef PARALLEL
- #define zprintf dprintf
- extern VOID dprintf(STRPTR,...);
- #else
- #define zprintf kprintf
- extern VOID kprintf(STRPTR,...);
- #endif
-
- #ifdef DEBUG
- #define D(x) x
- #else
- #define D(x) ;
- #endif
-
- /* Local protos */
- VOID main(VOID);
- BOOL InstallWedge(VOID);
- BOOL RemoveWedge(VOID);
- struct JumpTable *GetJumpTable(UBYTE *);
-
- /* Assembler stubs will return a pointer to the caller's stack in a4.
- * The only system function at this moment using a4 is the workbench.library
- * AddAppIconA() function.
- */
- #define ACALLER (0) /* StackPtr[0] = ACaller, StackPtr[1] = saved A6 in stub */
- #define CCALLER (2) /* StackPtr[2] = CCaller */
-
- /* The number of 'replacement' functions */
- #define NUMBEROFFUNCTIONS (4)
-
- /* prototypes for the functions to be SetFunction()'ed. */
-
- /* intuition.library */
- struct Screen *(*ASM oldOpenScreen) (REG(a0) struct NewScreen *,
- REG(a6) struct Library *);
- struct Window *(*ASM oldOpenWindowTagList) (REG(a0) struct NewWindow *,
- REG(a1) struct TagItem *,
- REG(a6) struct Library *);
- struct Screen *ASM newOpenScreen(REG(a0) struct NewScreen *,
- REG(a4) ULONG *,
- REG(a6) struct Library *);
- struct Window *ASM newOpenWindowTagList(REG(a0) struct NewWindow *,
- REG(a1) struct TagItem *,
- REG(a4) ULONG *,
- REG(a6) struct Library *);
-
- /* exec.library */
- VOID(*ASM oldFreeMem) (REG(a1) VOID *,
- REG(d0) ULONG,
- REG(a6) struct Library *);
- VOID ASM newFreeMem(REG(a1) VOID *,
- REG(d0) ULONG,
- REG(a4) ULONG *,
- REG(a6) struct Library *);
-
- /* graphics.library */
- VOID(*ASM oldSetFont) (REG(a1) struct RastPort *,
- REG(a0) struct TextFont *,
- REG(a6) struct Library *);
- VOID ASM newSetFont(REG(a1) struct RastPort *,
- REG(a0) struct TextFont *,
- REG(a4) ULONG *,
- REG(a6) struct Library *);
-
- /* Assembler Stubs */
- extern OpenScreenStub();
- extern OpenWindowTagListStub();
- extern FreeMemStub();
- extern SetFontStub();
-
- /* The LVO's to use from amiga.lib */
- extern LVOOpenScreen;
- extern LVOOpenWindowTagList;
- extern LVOFreeMem;
- extern LVOSetFont;
-
- extern struct ExecBase *SysBase;
- struct IntuitionBase *IntuitionBase;
- struct GfxBase *GfxBase;
-
- /* Use a table and an array to make it a little more generic and easier to
- * add functions.
- */
- struct LVOTable
- {
- LONG lt_LVO;
- struct Library *lt_LibBase;
- ULONG lt_oldFunction;
- ULONG lt_newFunction;
- };
-
- struct LVOTable LVOArray[] =
- {
- {&LVOOpenScreen, (struct Library *) &IntuitionBase,
- &oldOpenScreen,
- &OpenScreenStub},
- {&LVOOpenWindowTagList, (struct Library *) &IntuitionBase,
- &oldOpenWindowTagList, &OpenWindowTagListStub},
- {&LVOFreeMem, (struct Library *) & SysBase, &oldFreeMem, &FreeMemStub},
- {&LVOSetFont, (struct Library *) & GfxBase, &oldSetFont, &SetFontStub},
- };
-
- struct JumpTable
- {
- struct SignalSemaphore jt_Semaphore;
- UWORD pad_word;
- struct Task *jt_Owner;
- UBYTE jt_Function[NUMBEROFFUNCTIONS * 6];
- };
-
- /* Strings */
- /* The name this JumpTable/Semaphore will get. */
- static UBYTE *JTName = "ISpy-MiscJumpTable";
-
- static UBYTE *VersTag = "\0$VER: ISpy 37.4 (21.3.91)";
- static UBYTE *VerTitle = "Ispy 37.4";
- static UBYTE *Copyright = "Copyright (c) 1991 Commodore-Amiga, Inc.\n";
- static UBYTE *CBreak = "CTRL-C or BREAK to exit...\n";
- VOID
- main(VOID)
- {
-
- Write(Output(), (STRPTR) VerTitle, strlen((STRPTR) VerTitle));
- Write(Output(), Copyright, strlen(Copyright));
-
- if (SysBase->LibNode.lib_Version > 36)
- {
- if (IntuitionBase = OpenLibrary("intuition.library", 37))
- {
- if (GfxBase = OpenLibrary("graphics.library", 37))
- {
- if (InstallWedge())
- {
- Write(Output(), CBreak, strlen(CBreak));
- Wait(SIGBREAKF_CTRL_C);
- RemoveWedge();
- }
- CloseLibrary(GfxBase);
- }
- else
- Write(Output(), "Couldn't open graphics.library\n", 31);
- CloseLibrary(IntuitionBase);
- }
- else
- Write(Output(), "Couldn't open intuition.library\n", 32);
- }
- else
- Write(Output(), "Requires at least Kickstart 2.04\n", 33);
- }
-
-
- BOOL
- InstallWedge(VOID)
- {
- struct JumpTable *jumptable;
- ULONG *addressptr;
- UCOUNT i, j;
-
- Forbid();
-
- /* Get pointer to JumpTable. Create it if necessary */
- if (jumptable = GetJumpTable(JTName))
- {
- /* Try to get exclusive lock on semaphore, in case it already existed. */
- if (AttemptSemaphore((struct SignalSemaphore *) jumptable))
- {
- /* Make sure nobody else has function addresses in the jumptable */
- if (jumptable->jt_Owner == NULL)
- {
- jumptable->jt_Owner = FindTask(0);
- /* Don't want to disable any longer than necessary */
- Disable();
-
- for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
- {
- /* Replace addresses in the jumptable with my own. */
- addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i);
- (*((ULONG *) LVOArray[j].lt_oldFunction)) = (ULONG) * addressptr;
- *addressptr = (ULONG) LVOArray[j].lt_newFunction;
- D(zprintf("setting table to Function: 0x%lx\n", *addressptr));
- }
- Enable();
- }
- else
- Write(Output(), "Already running.\n", 16);
- ReleaseSemaphore((struct SignalSemaphore *) jumptable);
- }
- else
- Write(Output(), "Can't lock table.\n", 18);
- }
- else
- Write(Output(), "Can't create jumptable\n", 23);
- Permit();
- return ((BOOL) jumptable);
- }
-
- BOOL
- RemoveWedge(VOID)
- {
- struct JumpTable *jumptable;
- ULONG *addressptr;
- UCOUNT i, j;
-
- Forbid();
-
- if (jumptable = GetJumpTable(JTName))
- {
- D(zprintf("jumptable @ 0x%lx\n", jumptable));
-
- /* Check if this task owns this jumptable */
- if (jumptable->jt_Owner == FindTask(0))
- {
-
- /* Get the semaphore exclusively.
- * Depending on what got SetFunction()'ed this could take some time.
- * Also note that shared locks are used to indicate the code is
- * being executed and that shared locks can jump ahead of queue'ed
- * exclusive locks, adding to the waittime.
- */
- ObtainSemaphore((struct SignalSemaphore *) jumptable);
-
- Disable();
-
- /* Restore old pointers in jumptable */
-
- for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
- {
- addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i);
- *addressptr = (*((ULONG *) LVOArray[j].lt_oldFunction));
- D(zprintf("setting table to oldFunction: 0x%lx\n", *addressptr));
- }
-
- Enable();
-
- jumptable->jt_Owner = NULL;
- ReleaseSemaphore((struct SignalSemaphore *) jumptable);
- }
- }
-
- Permit();
-
- return (TRUE);
- }
-
- struct JumpTable *
- GetJumpTable(UBYTE * name)
- {
- struct JumpTable *jumptable;
- ULONG *addressptr;
- UWORD *jmpinstr;
- UBYTE *jtname;
- UCOUNT i, j;
-
- /* Not really necessary to forbid again, just to indicate that I don't
- * want another task to create the semaphore while I'm trying to do the
- * same. Here GetJumpTable() is only called from InstallWedge(), so it
- * will just bump the forbid count.
- */
- Forbid();
-
- if (!(jumptable = (struct JumpTable *) FindSemaphore(name)))
- {
- if (jumptable = AllocMem(sizeof(struct JumpTable), MEMF_PUBLIC | MEMF_CLEAR))
- {
- if (jtname = AllocMem(32, MEMF_PUBLIC | MEMF_CLEAR))
- {
-
- for (i = 0, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
- {
- jmpinstr = (UWORD *) ((UBYTE *) jumptable->jt_Function + i);
- *jmpinstr = 0x4EF9;
-
- addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i + 2);
- *addressptr = (ULONG) SetFunction(
- (struct Library *) (*((ULONG *) LVOArray[j].lt_LibBase)),
- LVOArray[j].lt_LVO,
- (VOID *) ((UBYTE *) jumptable->jt_Function + i));
- }
-
- jumptable->jt_Semaphore.ss_Link.ln_Pri = 0;
-
- strcpy(jtname, name);
- jumptable->jt_Semaphore.ss_Link.ln_Name = jtname;
- AddSemaphore((struct SignalSemaphore *) jumptable);
- /* In 1.2/1.3 AddSemaphore() didn't work properly.
- ** Under 1.2/1.3, change it to:
- ** InitSemaphore(jumptable);
- ** Forbid();
- ** Enqueue(&SysBase->SemaphoreList, jumptable);
- ** Permit();
- */
- }
- else
- {
- FreeMem(jumptable, sizeof(struct JumpTable));
- jumptable = NULL;
- }
- }
- }
-
- Permit();
-
- /* If succeeded, you now have a jumptable which entries point to the original
- * library functions. If another task SetFunction()'ed one or more of those
- * already, that task can never go away anymore.
- */
- return (jumptable);
- }
-
-
- /* Note: if you'd want this to work with 1.3, you wouldn't/couldn't lock the
- * semaphore, but instead would have to use a global to in- and decrement.
- * When exiting, you'd spin around the global counter, waiting for it to reach
- * zero. At that point you'd Disable(), reset the pointers in the jumptable and
- * Enable() again.
- */
-
-
- struct Screen *ASM
- newOpenScreen(REG(a0) struct NewScreen * newscreen,
- REG(a4) ULONG * stackptr,
- REG(a6) struct Library * base)
- {
- struct SignalSemaphore *jt;
- struct Screen *screen = NULL;
-
- /* Find the semaphore to lock shared, indicating the routine is being run. */
- /* For speed reasons you may want to cache the pointer to the semaphore
- ** in a global variable */
- if (jt = FindSemaphore(JTName))
- {
- /* Lock shared in 2.0. In 1.3 you'd increment a global counter */
- ObtainSemaphoreShared(jt);
- /* Simple test for valid argument. Could check all the fields too. */
- if (newscreen != NULL)
- {
- screen = (*oldOpenScreen) (newscreen, base);
- }
- else
- {
- ULONG ACaller = stackptr[ACALLER];
- ULONG CCaller = stackptr[CCALLER];
-
- Forbid(); /* To make sure the output isn't garbled */
- zprintf("OpenScreen(NULL) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
- SysBase->ThisTask->tc_Node.ln_Name,
- SysBase->ThisTask,
- ACaller,
- CCaller,
- stackptr);
- Permit();
- }
- /* Release shared lock. In 1.3 you'd decrement the global pointer */
- ReleaseSemaphore(jt);
- }
-
- return (screen);
- }
-
- struct Window *ASM
- newOpenWindowTagList(REG(a0) struct NewWindow * newwindow,
- REG(a1) struct TagItem * tags,
- REG(a4) ULONG * stackptr,
- REG(a6) struct Library * base)
- {
- struct SignalSemaphore *jt;
- struct Window *window = NULL;
-
-
- if (jt = FindSemaphore(JTName))
- {
- ObtainSemaphoreShared(jt);
- if (newwindow != NULL || tags != NULL)
- {
- window = (*oldOpenWindowTagList) (newwindow, tags, base);
- }
- else
- {
- ULONG ACaller = stackptr[ACALLER];
- ULONG CCaller = stackptr[CCALLER];
-
- Forbid();
- zprintf("OpenWindowTagList(NULL,NULL) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
- SysBase->ThisTask->tc_Node.ln_Name,
- SysBase->ThisTask,
- ACaller,
- CCaller,
- stackptr);
- Permit();
- }
- ReleaseSemaphore(jt);
- }
-
- return (window);
- }
-
-
- VOID ASM
- newFreeMem(REG(a1) VOID * memptr,
- REG(d0) ULONG size,
- REG(a4) ULONG * stackptr,
- REG(a6) struct Library * base)
- {
- struct SignalSemaphore *jt;
-
- if (jt = FindSemaphore(JTName))
- {
- ObtainSemaphoreShared(jt);
- if (memptr != NULL && size != 0L)
- {
- (*oldFreeMem) (memptr, size, base);
- }
- else
- {
- ULONG ACaller = stackptr[ACALLER];
- ULONG CCaller = stackptr[CCALLER];
-
- Forbid();
- zprintf("FreeMem(0x%lx,%ld) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
- memptr, size,
- SysBase->ThisTask->tc_Node.ln_Name,
- SysBase->ThisTask,
- ACaller,
- CCaller,
- stackptr);
- Permit();
- }
-
- ReleaseSemaphore(jt);
- }
- }
-
- VOID ASM
- newSetFont(REG(a1) struct RastPort * rp,
- REG(a0) struct TextFont * font,
- REG(a4) ULONG * stackptr,
- REG(a6) struct Library * base)
- {
- struct SignalSemaphore *jt;
-
-
- if (jt = FindSemaphore(JTName))
- {
- ObtainSemaphoreShared(jt);
- if (rp != NULL && font != NULL)
- {
- (*oldSetFont) (rp, font, base);
- }
- else
- {
- ULONG ACaller = stackptr[ACALLER];
- ULONG CCaller = stackptr[CCALLER];
-
- Forbid();
- zprintf("SetFont(0x%lx,0x%lx) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
- rp, font,
- SysBase->ThisTask->tc_Node.ln_Name,
- SysBase->ThisTask,
- ACaller,
- CCaller,
- stackptr);
- Permit();
- }
- ReleaseSemaphore(jt);
- }
- }
-
-
-
-
-
-
-
- ===================================================================
-
-
-
-
-
-
-
-
-
- **
- ** ISpy stubs
- **
- ** Copyright (c) 1991 Commodore-Amiga, Inc.
- ** All Rights Reserved
- **
- **
- INCLUDE "exec/types.i"
-
- SECTION CODE
-
- XREF _SysBase
-
- XREF _LVOForbid
- XREF _LVOPermit
-
- XREF _newOpenScreen
- XREF _newOpenWindowTagList
- XREF _newFreeMem
- XREF _newSetFont
-
- XDEF _OpenScreenStub
- XDEF _OpenWindowTagListStub
- XDEF _FreeMemStub
- XDEF _SetFontStub
-
-
- _OpenScreenStub:
- movem.l a4,-(sp)
- lea 4(sp),a4
- jsr _newOpenScreen
- movem.l (sp)+,a4
- rts
-
- _OpenWindowTagListStub:
- movem.l a4,-(sp)
- lea 4(sp),a4
- jsr _newOpenWindowTagList
- movem.l (sp)+,a4
- rts
-
- _FreeMemStub:
- movem.l a4,-(sp)
- lea 4(sp),a4
- jsr _newFreeMem
- movem.l (sp)+,a4
- rts
-
- _SetFontStub:
- movem.l a4,-(sp)
- lea 4(sp),a4
- jsr _newSetFont
- movem.l (sp)+,a4
- rts
-
- END
-